#include "ustc_comdef.h"
#include "ustc_custom.h"
#include "ustc_config.h"
#include "ustc_hif.h"
#include "ustc_api.h"
#include "i2c_drv.h"
#include "i2c_init.h"
#include "lcd_ili9320_16bit.h"

#define SAMPLING_INTERRUPT	1

#define FRAME_W 640
#define FRAME_H 480

#define WIN_W	480
#define WIN_H	480

#define IMG_W	176
#define IMG_H	176

USTC_U8 const i2c_w[]=
{
	#include "i2c_ov9650_init.txt"
};

CMR_PARA_T para_cmr;
USTC_CAMERA_T ustc_camera;
USTC_CAMERA_T *p_camera;

RESIZER_T resizer=
{
	0,0,
	WIN_W, WIN_H,
	0,0,
	IMG_W, IMG_H
};


#if (S3C44B0_TEST_PLATFORM==0)		//A7S
USTC_U16 *p_frame=(USTC_U16*)0x01000000;//0x0100000A;
#else
USTC_U16 *p_frame=(USTC_U16*)0x0C010000;//0x0100000A;
#endif

extern USTC_U32 VectorTable[];
extern unsigned int device_address;
extern STATUS_T i2c_write_buffer_s3c(I2C_REQ_T * i2c_req);
extern void lcd_init(void);

USTC_BOOL ustc_check_flag(USTC_BOOL val, USTC_BOOL *pFlag)
{
	__asm{
		SWP val, val, [pFlag]
	}
	
	return val;
}

void ustc_camera_get_data(USTC_CAMERA_T *pCamera)
{
	int i;
	USTC_U32 tmp=pCamera->wDataCnt;
	USTC_U16 *p=pCamera->pData;

//////////////////////////////////////////////////////////
////	read rgb data from CMIF entry
	for (i=0x400; i>0; i--)
		*p++=inph(HIF_CMIF_ENTRY);
	
	tmp+=0x400;

//////////////////////////////////////////////////////////
////	Check pointer to write buffer
	if (p>=pCamera->pEnd)
	{//rewind pointer
		p=pCamera->pStart;
	}

	pCamera->pData=p;
	pCamera->wDataCnt=tmp;
}

void __irq isr_ustc_camera(void)
{
#if 1
	UINT16 int_status=g_CUST->int_enable&ustc_int_status();
	USTC_U32 module_status;

	if (HIF_INT_STA_CMIF&int_status)
	{
		module_status=ustc_cmif_int_status();
		ustc_cmif_int_clear(module_status);
		
		g_CUST->frame_done++;

		if (p_camera->wDataCnt>=p_camera->wImageSize)
		{
			p_camera->bEnd=1;
			p_camera->wDataCnt-=p_camera->wImageSize;
			if (FRAME_BUFFER_COUNT>1)
			{
				p_camera->pDisp+=p_camera->wImageSize;
				if (p_camera->pDisp>=p_camera->pEnd)//rewind pointer to display
					p_camera->pDisp-=p_camera->wBufSize;
			}
		}
	}
#endif
//////////////////////////////////////////////////////////
////	Clear INT
	ustc_int_clear(HIF_INT_STA_CMIF_R|HIF_INT_STA_CMIF_W|HIF_INT_STA_ERR);

#if (S3C44B0_TEST_PLATFORM>0)
	*(unsigned long*)0x1D20054=1;//clear EINT4 pending
	*(unsigned long*)0x1E00024=0x200000;//clear EINT4 pendding
#endif

	if (HIF_INT_STA_CMIF_W&int_status)
		ustc_camera_get_data(p_camera);
}


STATUS_T i2c_write_buffer_s3c(I2C_REQ_T *i2c_req)
{
	USTC_U8 *pbuf;
	STATUS_T status = RSP_SUCCESS;
	int i;
	
	for (i=0;i<i2c_req->data_size;i+=i2c_req->p_para_i2c->len_per_write)
	{	
		pbuf = i2c_req->data + i;

		i2c_write_data((unsigned int)pbuf[0],(unsigned int)pbuf[1]);

		ustc_delay(i2c_req->p_para_i2c->access_interval);
	}
	return status;
}

void sensor_init()
{
	STATUS_T ret=0;

	I2C_REQ_T i2c_req;
	I2C_PARA_T para_i2c;
	I2C_PARA_T *p_i2c_para=&para_i2c;

	p_i2c_para->slave_addr = 0x60;
	p_i2c_para->len_per_write = 2;
	p_i2c_para->len_per_read =  1;
	
	p_i2c_para->options = I2C_ACK;
	p_i2c_para->timming =  0x7c1120e0;
	p_i2c_para->access_interval = 0x2000;
	p_i2c_para->retry_time = 3;

	i2c_req.p_para_i2c=&para_i2c;
	i2c_req.data = (USTC_U8*)i2c_w;
	i2c_req.data_size=sizeof(i2c_w);
	i2c_req.result=0;

	p_i2c_para->len_per_write=2;

#if (S3C44B0_TEST_PLATFORM==0)		//A7S
	ret=i2c_write_buffer(&i2c_req);
#else

	lcd_init();
//	dl_lcd_ILI9320_16BIT_set_scanmode(1);
	device_address=p_i2c_para->slave_addr;

	sensor_powerdown(1);
	sensor_powerdown(0);

	sensor_reset(1);
	sensor_reset(0);
	
	i2c_config(1);

	ret=i2c_read_data(0x0A);
	ret=i2c_read_data(0x0B);
	ret=i2c_write_buffer_s3c(&i2c_req);
#endif

}

void ustc_camera_preview(USTC_CAMERA_T *pCamera)
{
	USTC_U32 sys_ctrl;
	USTC_U32 count;
	int i;

#if 0//(SAMPLING_INTERRUPT>0)
	for (i=pCamera->wBlankFrame; i>0; i--)
	{
		while (0==ustc_check_flag(0, (USTC_BOOL*)&p_camera->bEnd))
			;

//		USTC_IO_OUTW(CMR_SEN_IF_SEL,CMR_SEN_IF_SEL_SENSOR_IF_ENANLE);
		ustc_camera_reset(pCamera);
	}
#endif

	while (1)
	{
		USTC_U16 *p;

		ustc_delay(1000);
		
		do{
#if (SAMPLING_INTERRUPT==0)
			while (!(HIF_INT_STA_CMIF_W&ustc_int_status()))
				;
			ustc_int_clear(HIF_INT_STA_CMIF_W);
			
			ustc_camera_get_data(p_camera);
#endif
		}while (0==ustc_check_flag(0, (USTC_BOOL*)&p_camera->bEnd));

		if (FRAME_BUFFER_COUNT<2)
		{
			USTC_U32 remain_cnt=0;
			
			remain_cnt=ustc_cfifo_data_count();
			if (remain_cnt)
			{
				ustc_cfifo_set();
				for (i=remain_cnt*2; i>0; i--)
					*p_camera->pData++=inph(HIF_CMIF_ENTRY);

				ustc_cfifo_reset();
			}
			ustc_sw_reset_enter(HIF_RST_CMIF_LOGIC);
		}

/////////////////////////////////////////////////////////////
//		Dsiplay frame
//
//		dl_lcd_ILI9320_16BIT_display_scn((240-IMG_W)/2, (320-IMG_H)/2, IMG_W, IMG_H, (USTC_U8*)p_frame);
#if (S3C44B0_TEST_PLATFORM>0)		//S3C44B0

		p=(USTC_U16*)p_camera->pDisp;

		count=p_camera->wImageSize;
		if (FRAME_BUFFER_COUNT>1)
		{
			if (count>p_camera->pEnd-p)
				count=p_camera->pEnd-p;
		}
		
		for (i=0; i<count; i++)
		{
			LCD_DATA_WRITE_ILI9320_16BIT(*(p++));
		}

		p=p_camera->pStart;

		for (; i<p_camera->wImageSize; i++)
		{
			LCD_DATA_WRITE_ILI9320_16BIT(*(p++));
		}
#endif
/////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////
//		re-enable CMIF if single frame buffer
/////////////////////////////////////////////////////////////
		if (FRAME_BUFFER_COUNT<2)
		{//re-enable CMIF
			ustc_sw_reset(HIF_RST_CFIFO, 1);
			ustc_sw_reset_exit(HIF_RST_CMIF_LOGIC);
		}
	}
}

extern USTC_U16 ustc_tp_control_reg;

#ifndef _TEST_PATTERN_
int test_camera()
#else
int c_main()
#endif
{
	USTC_U32 sys_ctrl;
	STATUS_T ret=0;
	int i=0;
	
	ustc_tp_init();

	ustc_outh(HIF_PLL_CFG, 0x2F0C);

	ustc_delay(100000);

	ustc_clk_enable(HIF_CLK_EN_CMIF|HIF_CLK_EN_CMIF_RAM);

//	ustc_cfg_cmr_snr_clk(0x11, 2, 0);
	ustc_cfg_cmr_tv_clk(0x11, 2, 0);
//	ustc_cfg_cmif_clk(HIF_CMR_MCLK_EN|HIF_CMR_PCLK_EXT, 2, 0);//external pclk

	ustc_sw_reset_enter(HIF_RST_SD|HIF_RST_SD_REG|HIF_RST_USB|HIF_RST_CMIF_LOGIC|HIF_RST_CMIF_REG);
	ustc_sw_reset_exit(HIF_RST_CMIF_LOGIC|HIF_RST_CMIF_REG);
	
	ustc_cfg_yrc_para(0x67b7,0xc658);

	ustc_sys_ctrl(0x118);//enable YUV2RGB
//	ustc_sys_ctrl(0x108);//disable YUV2RGB
	
	sensor_init();

	ustc_memset((void*)&para_cmr, 0, sizeof(CMR_PARA_T));
	ustc_memset((void*)&ustc_camera, 0, sizeof(USTC_CAMERA_T));
	
	ustc_delay(100000);

	if (!ret)
	{
		para_cmr.hsync_shape = 0;
		para_cmr.vsync_shape = 0;
		para_cmr.yuv_format = 2;
		para_cmr.frame_sample_intv=0;

		p_camera=&ustc_camera;

		ustc_outh(HIF_INT_MASK, 0xFFFF);
		if (SAMPLING_INTERRUPT>0)//enable INT on CUST
		{
			//redirect ISR
			VectorTable[13]=(USTC_U32)isr_ustc_camera;
			enable_irq(0);//Enable IRQ or ARM
		}

		g_CUST->frame_done=0;
		g_CUST->overflow=0;
		
		p_camera->wSensorSize=((FRAME_H)<<16)|(FRAME_W);
		p_camera->wFitMode=2;
		
		ustc_camera_scale(p_camera, &resizer);

		resizer.t_w = (resizer.t_w+1)&(~1);
		
#if (S3C44B0_TEST_PLATFORM>0)
		*(unsigned long*)0x1D20054=1;//clear EINT4 pending
		*(unsigned long*)0x1E00024=0x200000;//clear EINT4 pendding
		
		dl_lcd_ILI9320_16BIT_set_disp_win(1, 0, 0, resizer.t_w, resizer.t_h);	
#endif

		ustc_camera_init_hw(p_camera, resizer.t_w, resizer.t_h, FRAME_BUFFER_COUNT);
		ustc_camera_init_sw(p_camera, p_frame, 1);
		p_camera->clk_cfg=*(USTC_U16*)&para_cmr;

		ustc_camera_open(p_camera);

		ustc_delay(100000);
		
		ustc_sw_reset_enter(HIF_RST_CMIF_LOGIC);

		if (SAMPLING_INTERRUPT>0)//enable INT on CUST
		{
			//clear CMIF Write INT
			ustc_int_clear(HIF_INT_CLR_ALL);
			//enable CMIF Write INT
			g_CUST->int_enable=HIF_INT_STA_CMIF_W|HIF_INT_STA_CMIF;//|HIF_INT_STA_ERR;//;
			ustc_int_enable(HIF_INT_STA_CMIF_W|HIF_INT_STA_CMIF);
		}

		ustc_sw_reset_exit(HIF_RST_CMIF_LOGIC);

		ustc_camera_preview(p_camera);
		
		ustc_cmif_close();
	}
	
	return ret;
}

